<html>
<head>
  <title>GraphML Change Log</title>
  <link rel="stylesheet" type="text/css" href="doc/graphml.css"/>
  <link rel="stylesheet" type="text/css" href="doc/ystyle.css"/>
</head>
<body>

<h1>Migration guide for GraphML extension package releases prior to 3.0</h1>

<p>This document provides an overview over the changes that are needed to adapt code that has been written against
  previous releases of the GraphML extension package. It focuses on custom implementations of the interfaces
  <a href="doc/api/yext/graphml/graph2D/NodeRealizerSerializer.html">NodeRealizerSerializer</a>,
  <a href="doc/api/yext/graphml/graph2D/EdgeRealizerSerializer.html">EdgeRealizerSerializer</a> and <a href="doc/api/org/graphdrawing/graphml/writer/OutputHandler.html">OutputHandler</a>.
  A concise list of all API changes can be found in the <a href="CHANGES.html">ChangeLog</a>.</p>

<h2>Overview</h2>

<p>Most API changes originate from the fact that class <code>org.graphdrawing.graphml.writer.IndentPrintWriter</code>
  has been replaced by the new interface <a href="doc/api/org/graphdrawing/graphml/writer/XmlWriter.html">XmlWriter</a>. Instead of the low-level string
  composition approach that has been used by the writer class, the new interface offers a number of higher level methods
  for structured creation of XML content, including automatic output escaping, namespace handling and more flexible
  output formats.
</p>

<p>
  Basically, the necessary steps to convert a custom <code>RealizerSerializer</code> or <code>OutputHandler</code>
  implementation
  are as follows:
  <ol>
    <li>
      Adapt to the new contract of these interfaces. Mostly, this consists of changing all signatures to use
      <code>XmlWriter</code> instead of <code>IndentPrintWriter</code>.
    </li>
    <li>Modify your serialization code to use the higher level methods of <code>XmlWriter</code> instead of composing
      the
      result string and writing it directly to the <code>IndentPrintWriter</code></li>
    <li>If necessary, implement/customize the new methods in the <code>RealizerSerializer</code> interfaces</li>
    <li>Optionally, register your custom <code>RealizerSerializer</code> at a specific
      <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html">GraphMLIOHandler</a> instance
      instead of global registration.
    </li>
  </ol>
</p>
<p>
  The following paragraphs show these steps in more detail. We assume that you want to convert the class
  <a href="doc/api/demo/yext/graphml/CustomNodeRealizerSerializer.html">CustomNodeRealizerSerializer</a> to the new GraphML API. Adaption to custom <code>OutputHandler</code>
  implementations should be straightforward.
</p>

<h2>Step 1: Change method signatures</h2>

<p>
  The following method signatures have changed for the <code>RealizerSerializer</code> interfaces and must be converted:
  <table>
    <tbody>
      <tr>
        <th>
          Before
        </th>
        <th>After</th>
      </tr>
      <tr>
        <td>
          <tt>public void write(NodeRealizer realizer, <b>IndentPrintWriter ipw</b>, GraphMLWriteContext context);</tt>
        </td>
        <td>
          <tt>public void write(NodeRealizer realizer, <b>XmlWriter writer</b>, GraphMLWriteContext context);</tt>
        </td>
      </tr>
      <tr>
        <td>
          <tt>public void writeAttributes(NodeRealizer realizer, <b>IndentPrintWriter ipw</b>, GraphMLWriteContext
            context);</tt>
        </td>
        <td>
          <tt>public void writeAttributes(NodeRealizer realizer, <b>XmlWriter writer</b>, GraphMLWriteContext context);</tt>
        </td>
      </tr>
    </tbody>
  </table>
</p>

<h2>Step 2: Change the custom serialization code to the XmlWriter API</h2>

<p>
  For example, the <code>write</code> method body needs to be changed from:
</p>

<div class="example"><a name="ex_cnr_before"></a>

  <p class="title">
    <b>Example&nbsp;1&nbsp;Before conversion</b>
  </p><pre class="programlisting"><span class="java_keyword">public void</span> <span
    class="java_methodCall">write</span><span class="java_separator">(</span>NodeRealizer realizer, IndentPrintWriter writer, GraphMLWriteContext context<span
    class="java_separator">)</span>
<span class="java_separator">{</span>
  <span class="java_keyword">super</span><span class="java_separator">.</span><span class="java_methodCall">write</span><span
    class="java_separator">(</span>realizer, writer, context<span class="java_separator">)</span>;
  CustomNodeRealizer fnr <span class="java_operator">=</span> <span
    class="java_separator">(</span>CustomNodeRealizer<span class="java_separator">)</span>realizer;
  ipw<span class="java_separator">.</span><span class="java_methodCall">println</span><span
    class="java_separator">(</span>"<span class="java_stringLiteral">&lt;custom:CustomElement value=\"</span>" <span
    class="java_operator">+</span> fnr<span class="java_separator">.</span>customValue <span
    class="java_operator">+</span> "<span class="java_stringLiteral">\"/></span>"<span class="java_separator">)</span>;
<span class="java_separator">}</span>
 </pre>
</div>
<p>to the new write methods:</p>

<div class="example"><a name="ex_cnr_after"></a>

  <p class="title">
    <b>Example&nbsp;2&nbsp;After conversion</b>
  </p><pre class="programlisting"><span class="java_keyword">public void</span> <span
    class="java_methodCall">write</span><span class="java_separator">(</span>NodeRealizer realizer, XmlWriter writer, GraphMLWriteContext context<span
    class="java_separator">)</span>
<span class="java_separator">{</span>
  <span class="java_keyword">super</span><span class="java_separator">.</span><span class="java_methodCall">write</span><span
    class="java_separator">(</span>realizer, writer, context<span class="java_separator">)</span>;
  CustomNodeRealizer fnr <span class="java_operator">=</span> <span
    class="java_separator">(</span>CustomNodeRealizer<span class="java_separator">)</span>realizer;
  writer<span class="java_separator">.</span><span class="java_methodCall">writeStartElement</span><span
    class="java_separator">(</span>"<span class="java_stringLiteral">CustomElement</span>", <span
    class="java_methodCall">getNamespaceURI</span><span class="java_separator">())</span>
        <span class="java_separator">.</span><span class="java_methodCall">writeAttribute</span><span
    class="java_separator">(</span>"<span class="java_stringLiteral">value</span>", fnr<span
    class="java_separator">.</span><span class="java_methodCall">customValue</span><span class="java_separator">)</span>
        <span class="java_separator">.</span><span class="java_methodCall">writeEndElement</span><span
    class="java_separator">()</span>;
<span class="java_separator">}</span>
 </pre>
</div>
<p>
  You can see that instead of piecing the result string together by hand (including manual quoting etc.), higher level
  method calls
  are used that describe the structure of the resulting XML document. Some points to keep in mind when doing the
  conversion:
  <ul>
    <li>
      All methods are namespace aware. The <code>RealizerSerializer</code> interfaces contain a new method <code>getNamespaceURI()</code>
      that allows to specify a namespace URI for the serializer, as can be seen from the example. The method overloads
      without a prefix
      determine the namespace prefix automatically, either from a prefix that has been set in an enclosing set of
      elements or a declaration that has been set with
      <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html#addNamespace()">addNamespace</a>. If neither can be found, the prefix will bound to the
      default namespace
      for the current scope. The element names in calls to
      <a href="doc/api/org/graphdrawing/graphml/writer/XmlWriter.html#writeStartElement(String,String)">writeStartElement</a> and overloads
      should <b>not</b> be prefixed, instead use the overload that allows to specify a namespace prefix.
    </li>
    <li>
      Elements must be nested properly, as this would be the case in the resulting XML document. This also applies to
      attributes
      and text content, which always will be attached to the nearest open element.
    </li>
    <li>
      Text written by <a href="doc/api/org/graphdrawing/graphml/writer/XmlWriter.html#writeText(String)">writeText</a> content is automatically escaped.
    </li>
    <li>
      Subsequent calls to XmlWriter methods can be chained.
    </li>
  </ul>
</p>
<p>
  The following table gives a short overview over the most important methods that are currently part of the <code>XmlWriter</code>
  interface:
  <table>
    <tbody>
      <tr>
        <th>
          Method
        </th>
        <th>Semantic</th>
      </tr>
      <tr>
        <td>
          <tt>writeStartDocument(String prefix, String docTag, String nsURI)</tt>
        </td>
        <td>
          Start a new document, calling other output methods before this has been called has undefined results. This
          method is usually
          only called by the framework.
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeStartElement(String nsPrefix, String localName, String ns)</tt><br/>
          <tt>writeStartElement(String localName, String ns)</tt>
        </td>
        <td>
          Begin a new XML element with given parameters, the second variant determines the prefix automagically
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeAttribute(String prefix, String localName, String ns, String value)</tt><br/>
          <tt>writeAttribute(String localName, String value)</tt>
        </td>
        <td>
          Write a XML attribute, which will be attached to the nearest open element.
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeText(String text)</tt>
        </td>
        <td>
          Write XML text content. Special XML characters in <tt>text</tt> will be escaped automatically.
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeRaw(String text)</tt>
        </td>
        <td>
          Write raw content. No escaping occurs. <tt>text</tt> must represent a collection of wellformed XML nodes.
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeEndElement()</tt>
        </td>
        <td>
          Close a XML element previously opened with <tt>writeStartElement</tt>
        </td>
      </tr>
      <tr>
        <td>
          <tt>writeEndDocument()</tt>
        </td>
        <td>
          Close the output, calling other output methods after this has been called has undefined results. This method
          is usually
          only called by the framework.
        </td>
      </tr>
    </tbody>
  </table>
</p>
<p>
  For interface <a href="doc/api/org/graphdrawing/graphml/writer/OutputHandler.html">OutputHandler</a>, the following methods need to be changed:
  <table>
    <tbody>
      <tr>
        <th>
          Before
        </th>
        <th>After</th>
      </tr>
      <tr>
        <td>
          <tt>public <b>String getKeyAttributes(GraphMLWriteContext context)</b>;</tt>
        </td>
        <td>
          <tt>public <b>void printKeyAttributes(GraphMLWriteContext context, XmlWriter writer)</b>;</tt>
        </td>
      </tr>
      <tr>
        <td>
          <tt>public void printKeyOutput(GraphMLWriteContext context, <b>IndentPrintWriter ips</b>);</tt>
        </td>
        <td>
          <tt>public void printKeyOutput(GraphMLWriteContext context, <b>XmlWriter writer</b>);</tt>
        </td>
      </tr>
      <tr>
        <td>
          <tt>public <b>String getDataAttributes(GraphMLWriteContext context)</b>;</tt>
        </td>
        <td>
          <tt>public <b>void printDataAttributes(GraphMLWriteContext context, XmlWriter writer)</b>;</tt>
        </td>
      </tr>
      <tr>
      <tr>
        <td>
          <tt>public void printDataOutput(GraphMLWriteContext context, <b>IndentPrintWriter ips</b>);</tt>
        </td>
        <td>
          <tt>public void printDataOutput(GraphMLWriteContext context, <b>XmlWriter writer</b>);</tt>
        </td>
      </tr>
    </tbody>
  </table>
</p>
<h2>Step 3: Implement new methods</h2>

<p>
  There is one new method in the <code>RealizerSerializer</code> interfaces that must be implemented:
</p>

<p>
  <ul>
    <li>
      <a href="doc/api/yext/graphml/graph2D/EdgeRealizerSerializer.html#getNamespacePrefix()">getNamespacePrefix</a> or
      <a href="doc/api/yext/graphml/graph2D/NodeRealizerSerializer.html#getNamespacePrefix()">getNamespacePrefix</a>, respectively:
      Return the target namespace of the toplevel element of the serialized realizer representation.
    </li>
  </ul>
</p>
<p>
  For the new methods <code>getNamespacePrefix()</code>, <code>canHandle(NodeRealizer nr, GraphMLWriteContext
  context)</code>,
  <code>canHandle(Node n, GraphMLParseContext context)</code>
  and <code>createRealizerInstance(Node node, GraphMLParseContext context)</code>, the abstract base classes
  <a href="doc/api/yext/graphml/graph2D/AbstractEdgeRealizerSerializer.html">AbstractEdgeRealizerSerializer</a>
  and <a href="doc/api/yext/graphml/graph2D/AbstractNodeRealizerSerializer.html">AbstractNodeRealizerSerializer</a> already provide default implementations that are backward
  compatible.
</p>

<p>
  <b>Note:</b> Usually, you do <b>not</b> want to override <code>getNamespacePrefix()</code> - instead, declare the
  namespace with
  <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html#addNamespace()">addNamespace</a>.
</p>

<h2>Step 4: Register your custom RealizerSerializer</h2>

<p>The static registration methods
  <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html#addEdgeRealizerSerializer(yext.graphml.graph2D.EdgeRealizerSerializer)">addEdgeRealizerSerializer</a>
  and <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html#addNodeRealizerSerializer(yext.graphml.graph2D.NodeRealizerSerializer)">addNodeRealizerSerializer</a>
  have been deprecated
  in favour of instance bound registration by means of class <a href="doc/api/yext/graphml/graph2D/RealizerSerializerManager.html">RealizerSerializerManager</a>. This
  class provides
  fine grained control over the registration of <code>RealizerSerializer</code> instances. An instance of this class
  which is bound
  to the current <code>GraphMLIOHandler</code> instance can be retrieved with
  <a href="doc/api/yext/graphml/graph2D/GraphMLIOHandler.html#getRealizerSerializerManager()">getRealizerSerializerManager</a>
</p>

<p>Points to keep in mind:</p>
<ul>
  <li>For a given <code>Node/EdgeRealizer</code> instance, all registered <code>RealizerSerializer</code> instances are
    queried in reverse
    order of registration, and the first instance where <code>canHandle(NodeRealizer nr, GraphMLWriteContext
    context)</code> returns <code>true</code> will be used. This allows for concurrent registration of multiple <code>RealizerSerializer</code>
    instances for the same <code>Realizer</code> type.
  </li>
  <li>
    The same comment applies to input handling, here <code>canHandle(Node n, GraphMLParseContext context)</code> is
    queried for a given DOM node.
  </li>
  <li>
    <code>RealizerSerializer</code>s registered with the deprecated static registration methods will be used as fallback
    instances, i.e.
    only when previous steps do not yield a matching implementation.
  </li>
</ul>
</body>
</html>
